"""
百度网盘登录状态管理模块

提供百度网盘的登录状态检查、登录引导、会话保持等功能
"""

import asyncio
import json
import os
import sys
from typing import Optional, Dict, Any
from datetime import datetime, timedelta
from playwright.async_api import Page, BrowserContext
from pathlib import Path

# 添加项目根目录到Python路径
project_root = Path(__file__).parent.parent.parent
sys.path.insert(0, str(project_root))

try:
    from src.utils.logger import get_logger
    from src.exceptions.exceptions import AuthException
    from src.config.settings import BaiduAuthConfig
except ImportError:
    # 如果绝对导入失败，尝试相对导入
    try:
        from ..utils.logger import get_logger
        from ..exceptions.exceptions import AuthException
        from ..config.settings import BaiduAuthConfig
    except ImportError:
        # 最后尝试直接导入
        from utils.logger import get_logger
        from exceptions.exceptions import AuthException
        from config.settings import BaiduAuthConfig

logger = get_logger(__name__)


class BaiduAuthManager:
    """百度网盘登录状态管理器"""
    
    def __init__(self, context: BrowserContext, config: Optional[BaiduAuthConfig] = None):
        """
        初始化认证管理器
        
        Args:
            context: 浏览器上下文
            config: 百度认证配置，如果不提供则使用默认配置
        """
        self.context = context
        self.config = config or BaiduAuthConfig()
        self.session_file = self.config.session_file
        self.login_url = self.config.login_url
        self.is_logged_in = False
        self.user_info: Optional[Dict[str, Any]] = None
        self._pending_cookies = []  # 待恢复的cookies
        
        # 确保数据目录存在
        os.makedirs(os.path.dirname(self.session_file), exist_ok=True)
    
    async def check_login_status(self, page: Page, use_saved_session: bool = True) -> bool:
        """
        基于STOKEN检查当前登录状态
        
        Args:
            page: 页面对象
            use_saved_session: 是否使用保存的会话
            
        Returns:
            bool: 是否已登录
        """
        try:
            logger.info("🔍 开始检查百度网盘登录状态（基于STOKEN）...")
            
            # 如果启用会话恢复且有待恢复的cookies，先恢复
            if use_saved_session and hasattr(self, '_pending_cookies') and self._pending_cookies:
                await self.context.add_cookies(self._pending_cookies)
                self._pending_cookies = []
                logger.info("✅ 已恢复保存的cookies")
            
            # 导航到百度网盘首页
            await page.goto(self.login_url, wait_until="networkidle")
            await asyncio.sleep(2)
            
            # 获取当前页面的所有cookies
            current_cookies = await self.context.cookies()
            
            # 检查是否存在STOKEN cookie
            stoken_cookie = None
            bduss_cookie = None
            
            for cookie in current_cookies:
                if cookie['name'] == 'STOKEN':
                    stoken_cookie = cookie
                    logger.info(f"🔑 检测到STOKEN: {cookie['value'][:20]}...")
                elif cookie['name'] == 'BDUSS':
                    bduss_cookie = cookie
                    logger.info(f"🔑 检测到BDUSS: {cookie['value'][:20]}...")
            
            # 如果存在STOKEN，说明用户已登录
            if stoken_cookie and stoken_cookie['value']:
                logger.info("✅ 检测到STOKEN，用户已登录")
                self.is_logged_in = True
                
                # 提取用户信息
                await self._extract_user_info(page)
                
                # 保存完整的会话信息（包括所有cookies）
                if not use_saved_session:
                    await self._save_session_with_cookies(current_cookies)
                    logger.info("💾 已保存完整的登录会话信息")
                
                return True
            
            # 如果没有STOKEN，检查是否在登录页面
            current_url = page.url
            if "passport.baidu.com" in current_url or "login" in current_url:
                logger.info("❌ 当前在登录页面，用户未登录")
                self.is_logged_in = False
                return False
            
            # 检查页面是否显示登录按钮
            login_indicators = [
                ".nd-main-header .nd-login-btn",
                ".wp-s-header__login", 
                "a[href*='passport.baidu.com']",
                ".login-btn",
                "button:has-text('登录')"
            ]
            
            for selector in login_indicators:
                try:
                    element = await page.wait_for_selector(selector, timeout=2000)
                    if element and await element.is_visible():
                        logger.info(f"❌ 检测到登录按钮: {selector}，用户未登录")
                        self.is_logged_in = False
                        return False
                except:
                    continue
            
            # 最终判断：没有STOKEN就认为未登录
            logger.warning("⚠️ 未检测到STOKEN，认为用户未登录")
            self.is_logged_in = False
            return False
            
        except Exception as e:
            logger.error(f"💥 检查登录状态失败: {str(e)}")
            self.is_logged_in = False
            return False
    
    async def _extract_user_info(self, page: Page) -> None:
        """
        提取用户信息
        
        Args:
            page: 页面对象
        """
        try:
            user_info = {}
            
            # 尝试获取用户名
            username_selectors = [
                ".nd-main-header .username",
                ".wp-s-header__user-info .username",
                "[data-button-id='b-header-user-menu'] .text"
            ]
            
            for selector in username_selectors:
                try:
                    element = await page.wait_for_selector(selector, timeout=2000)
                    if element:
                        username = await element.text_content()
                        if username and username.strip():
                            user_info["username"] = username.strip()
                            break
                except:
                    continue
            
            # 尝试获取头像URL
            avatar_selectors = [
                ".nd-main-header .nd-avatar img",
                ".wp-s-header__user-info img"
            ]
            
            for selector in avatar_selectors:
                try:
                    element = await page.wait_for_selector(selector, timeout=2000)
                    if element:
                        avatar_url = await element.get_attribute("src")
                        if avatar_url:
                            user_info["avatar_url"] = avatar_url
                            break
                except:
                    continue
            
            user_info["login_time"] = datetime.now().isoformat()
            self.user_info = user_info
            
            logger.info(f"用户信息提取完成: {user_info.get('username', '未知用户')}")
            
        except Exception as e:
            logger.warning(f"提取用户信息失败: {str(e)}")
    
    async def _save_session_with_cookies(self, cookies: list) -> None:
        """
        保存完整的会话信息（包括所有cookies）
        
        Args:
            cookies: 页面的所有cookies
        """
        try:
            # 获取浏览器上下文的状态
            state = await self.context.storage_state()
            
            # 创建会话数据
            session_data = {
                'cookies': cookies,
                'storage_state': state,
                'timestamp': datetime.now().isoformat(),
                'user_info': self.user_info,
                'stoken_present': any(cookie['name'] == 'STOKEN' for cookie in cookies),
                'bduss_present': any(cookie['name'] == 'BDUSS' for cookie in cookies)
            }
            
            # 保存到文件
            with open(self.session_file, 'w', encoding='utf-8') as f:
                json.dump(session_data, f, ensure_ascii=False, indent=2)
            
            logger.info(f"💾 已保存完整会话信息到: {self.session_file}")
            logger.info(f"📊 会话包含 {len(cookies)} 个cookies")
            
        except Exception as e:
            logger.error(f"💥 保存会话失败: {str(e)}")

    async def _save_session(self, page: Page) -> None:
        """
        保存会话信息（兼容旧版本）
        
        Args:
            page: 页面对象
        """
        try:
            # 获取当前页面的cookies
            cookies = await self.context.cookies()
            await self._save_session_with_cookies(cookies)
            
        except Exception as e:
            logger.error(f"💥 保存会话失败: {str(e)}")
    
    def load_session(self) -> bool:
        """
        加载保存的会话信息（基于STOKEN验证）
        
        Returns:
            bool: 是否成功加载会话
        """
        try:
            if not os.path.exists(self.session_file):
                logger.info("📂 未找到保存的会话文件")
                return False
            
            with open(self.session_file, 'r', encoding='utf-8') as f:
                session_data = json.load(f)
            
            # 检查会话数据完整性
            if 'cookies' not in session_data:
                logger.warning("⚠️ 会话文件格式不正确，缺少cookies信息")
                return False
            
            cookies = session_data['cookies']
            
            # 验证是否包含STOKEN
            has_stoken = False
            has_bduss = False
            
            for cookie in cookies:
                if cookie['name'] == 'STOKEN' and cookie['value']:
                    has_stoken = True
                    logger.info(f"🔑 会话包含有效STOKEN: {cookie['value'][:20]}...")
                elif cookie['name'] == 'BDUSS' and cookie['value']:
                    has_bduss = True
                    logger.info(f"🔑 会话包含有效BDUSS: {cookie['value'][:20]}...")
            
            if not has_stoken:
                logger.warning("⚠️ 会话中未找到有效的STOKEN，会话可能已过期")
                return False
            
            # 检查会话时间
            if 'timestamp' in session_data:
                save_time = datetime.fromisoformat(session_data['timestamp'])
                time_diff = datetime.now() - save_time
                
                if time_diff.days > 30:  # 30天过期
                    logger.warning(f"⚠️ 会话已过期 ({time_diff.days}天前保存)")
                    return False
                
                logger.info(f"📅 会话保存时间: {save_time.strftime('%Y-%m-%d %H:%M:%S')} ({time_diff.days}天前)")
            
            # 准备恢复cookies
            self._pending_cookies = cookies
            
            # 恢复用户信息
            if 'user_info' in session_data:
                self.user_info = session_data['user_info']
                logger.info(f"👤 已恢复用户信息: {self.user_info.get('username', '未知用户')}")
            
            logger.info("✅ 会话加载成功，等待应用到浏览器上下文")
            return True
            
        except Exception as e:
            logger.error(f"💥 加载会话失败: {str(e)}")
            return False
    
    def clear_session(self) -> None:
        """清除保存的会话信息"""
        try:
            if os.path.exists(self.session_file):
                os.remove(self.session_file)
                logger.info("会话文件已删除")
            
            self.user_info = None
            self.is_logged_in = False
            self._pending_cookies = []
            
            logger.info("会话信息已清除")
            
        except Exception as e:
            logger.warning(f"清除会话失败: {str(e)}")
    
    def get_user_info(self) -> Optional[Dict[str, Any]]:
        """获取用户信息"""
        return self.user_info
    
    async def guide_login(self, page: Page, timeout: Optional[int] = None) -> bool:
        """
        引导用户登录
        
        Args:
            page: 页面对象
            timeout: 超时时间（秒），如果不提供则使用配置中的值
            
        Returns:
            bool: 是否登录成功
        """
        try:
            timeout = timeout or self.config.login_timeout
            check_interval = self.config.check_interval
            
            logger.info("开始引导用户登录百度网盘...")
            
            # 导航到登录页面
            await page.goto(self.login_url, wait_until="networkidle")
            await asyncio.sleep(2)
            
            # 如果已经在登录页面，直接等待
            current_url = page.url
            if "passport.baidu.com" not in current_url:
                # 尝试点击登录按钮
                login_selectors = [
                    ".nd-main-header .nd-login-btn",
                    ".wp-s-header__login",
                    "a[href*='passport.baidu.com']"
                ]
                
                login_clicked = False
                for selector in login_selectors:
                    try:
                        element = await page.wait_for_selector(selector, timeout=3000)
                        if element:
                            await element.click()
                            login_clicked = True
                            break
                    except:
                        continue
                
                if not login_clicked:
                    logger.warning("未找到登录按钮，可能已经登录或页面结构发生变化")
            
            # 等待用户完成登录
            logger.info(f"请在浏览器中完成登录操作（超时时间：{timeout}秒）...")
            print("\n" + "="*50)
            print("请在打开的浏览器窗口中完成百度网盘登录")
            print("登录完成后，程序将自动继续执行")
            print("="*50 + "\n")
            
            # 轮询检查登录状态
            start_time = datetime.now()
            while (datetime.now() - start_time).seconds < timeout:
                await asyncio.sleep(check_interval)
                
                if await self.check_login_status(page, use_saved_session=False):
                    logger.info("用户登录成功！")
                    return True
                
                # 检查是否还在登录相关页面
                current_url = page.url
                if "passport.baidu.com" not in current_url and "login" not in current_url:
                    # 可能已经跳转到主页，再次检查登录状态
                    if await self.check_login_status(page, use_saved_session=False):
                        logger.info("用户登录成功！")
                        return True
            
            logger.error(f"登录超时（{timeout}秒），请重试")
            return False
            
        except Exception as e:
            logger.error(f"引导登录失败: {str(e)}")
            return False
    
    async def ensure_logged_in(self, page: Page, redirect_url: str = None) -> bool:
        """
        确保用户已登录
        
        Args:
            page: 页面对象
            redirect_url: 登录成功后要跳转的URL
            
        Returns:
            bool: 是否已登录
        """
        try:
            # 1. 尝试加载保存的会话
            session_loaded = self.load_session()
            if session_loaded:
                logger.info("找到保存的会话，尝试验证有效性...")
                
                # 检查会话是否有效（使用保存的会话）
                if await self.check_login_status(page, use_saved_session=True):
                    logger.info("✅ 保存的会话有效，用户已登录")
                    
                    # 如果指定了跳转URL，则自动跳转
                    if redirect_url:
                        logger.info(f"🔄 自动跳转到目标页面: {redirect_url}")
                        try:
                            await page.goto(redirect_url, wait_until="domcontentloaded", timeout=60000)
                            await asyncio.sleep(3)
                        except Exception as e:
                            logger.warning(f"页面跳转超时，但继续执行: {str(e)}")
                            # 即使跳转超时，也尝试继续执行
                    
                    return True
                else:
                    logger.info("❌ 保存的会话无效，需要重新登录")
                    # 清除无效会话
                    self.clear_session()
            else:
                logger.info("未找到保存的会话")
            
            # 2. 检查当前登录状态（不使用保存的会话）
            if await self.check_login_status(page, use_saved_session=False):
                logger.info("✅ 用户已登录")
                # 保存当前会话
                await self._save_session(page)
                
                # 如果指定了跳转URL，则自动跳转
                if redirect_url:
                    logger.info(f"🔄 自动跳转到目标页面: {redirect_url}")
                    try:
                        await page.goto(redirect_url, wait_until="domcontentloaded", timeout=60000)
                        await asyncio.sleep(3)
                    except Exception as e:
                        logger.warning(f"页面跳转超时，但继续执行: {str(e)}")
                        # 即使跳转超时，也尝试继续执行
                
                return True
            
            # 3. 引导用户登录
            logger.info("用户未登录，开始引导登录...")
            login_success = await self.guide_login(page)
            
            # 如果登录成功且指定了跳转URL，则自动跳转
            if login_success and redirect_url:
                logger.info(f"🔄 登录成功，自动跳转到目标页面: {redirect_url}")
                try:
                    await page.goto(redirect_url, wait_until="domcontentloaded", timeout=60000)
                    await asyncio.sleep(3)
                except Exception as e:
                    logger.warning(f"页面跳转超时，但继续执行: {str(e)}")
                    # 即使跳转超时，也尝试继续执行
            
            return login_success
            
        except Exception as e:
            logger.error(f"确保登录状态失败: {str(e)}")
            return False